/**
 * @description 编译模板
 * @author xfj
 */

class CompilerTemp {
	constructor(el, data, methods) {
		this.data = data || {};
		this.methods = methods || {};
		this.compileTemp(el);
	}
	
	// 编译模板
	compileTemp(node) {
		if(node.childNodes.length === 0) {
			return;
		}
		const chilNodes = Array.from(node.childNodes);
		chilNodes.forEach(childNode => {
			if(this._isTextNode(childNode)) {
				// 是文本节点
				this._compileTextNode(childNode);
			} else if (this._isEleNode(childNode)) {
				// 是元素节点
				this._compileEleNode(childNode);
			}
			this.compileTemp(childNode);
		})
	}
	
	// 编译文本节点
	_compileTextNode(node) {
		const reg = /\{\{(\s*\w*\s*)}}/;
		const matchChildReg = reg.exec(node.textContent);
		if(matchChildReg === null) {
			return;
		}
		if(matchChildReg.length) {
			const key = RegExp.$1.trim();
			node.textContent = this.data[key];
			new Watch(this.data, key, (newValue) => {
				node.textContent = newValue;
			})
		}
	}
	
	// 编译元素节点
	_compileEleNode(node) {
		for(let key in node.attributes) {
			const attr = node.attributes[key];
			if(this._isEventDirective(attr.nodeName)) {
				// 判断是否是 v-on 指令
				const eventName = attr.nodeName.replace(/^v-on:/, '');
				this.updateEvent(eventName, attr.nodeValue, node);
			} else if(this._isCommonDirective(attr.nodeName)) {
				const attributeName = attr.nodeName.replace(/^v-/, '');
				const attributeValue = attr.nodeValue;
				this.update(attributeName, attributeValue, node);
			}
		}
	}
	
	// 解析指令对应的行为
	update(key, value, node) {
		const fn = this[`${key.toLocaleLowerCase()}Update`];
		fn.call(this, node, value);
	}
	// v-text 指令对应的解析
	textUpdate(node, key) {
		node.textContent = this.data[key];
		new Watch(this.data, key, (newValue) => {
			node.textContent = newValue;
		})
	}
	// v-model 指令对应的解析
	modelUpdate(node, key) {
		node.value = this.data[key];
		node.addEventListener('input', (e) => {
			this.data[key] = e.target.value;
		})
		new Watch(this.data, key, (newValue) => {
			node.value = newValue;
		})
	}
	// v-html 指令对应的解析
	htmlUpdate(node, key) {
		node.innerHTML = this.data[key];
		new Watch(this.data, key, (newValue) => {
			node.innerHTML = newValue;
		})
	}
	// v-on 指令对应的解析
	updateEvent(eventName, key, node) {
		node.addEventListener(eventName, this.methods[key]);
	}
	// 判断当前属性是否是普通指令
	_isCommonDirective(attribute) {
		return /^v-/.test(attribute);
	}// 判断当前属性是否是指令
	_isEventDirective(attribute) {
		return /^v-on:/.test(attribute);
	}
	
	// 判断是否是文本节点
	_isTextNode(node) {
		return node.nodeType === 3;
	}
	
	// 判断是否是元素节点
	_isEleNode(node) {
		return node.nodeType === 1;
	}
}
